/**
 * Copyright (c) 2014 Microsoft Open Technologies, Inc.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License"); you may
 *    not use this file except in compliance with the License. You may obtain
 *    a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 *    THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
 *    CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
 *    LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS
 *    FOR A PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT.
 *
 *    See the Apache Version 2.0 License for specific language governing
 *    permissions and limitations under the License.
 *
 *    Microsoft would like to thank the following companies for their review and
 *    assistance with these files: Intel Corporation, Mellanox Technologies Ltd,
 *    Dell Products, L.P., Facebook, Inc., Marvell International Ltd.
 *
 * @file    saiexperimental{{ sai_api.app_name | replace('_', '') }}.h
 *
 * @brief   This module defines SAI extensions for {{ sai_api.app_name | replace('_', ' ') | upper }}
 *
 * @warning This module is a SAI experimental module
 */

#if !defined (__SAIEXPERIMENTAL{{ sai_api.app_name | replace('_', '') | upper }}_H_)
#define __SAIEXPERIMENTAL{{ sai_api.app_name | replace('_', '') | upper}}_H_

#include <saitypesextensions.h>

/**
 * @defgroup SAIEXPERIMENTAL{{ sai_api.app_name | upper}} SAI - Experimental: {{ sai_api.app_name | replace('_', ' ') | upper }} specific API definitions
 *
 * @{
 */

{% for table in sai_api.tables %}
{% if table.actions | length > 1 or table.is_object == 'false' %}
/**
 * @brief Attribute data for #SAI_{{ table.name | upper }}_ATTR_ACTION
 */
typedef enum _sai_{{ table.name }}_action_t
{
{% for action in table.actions %}
    SAI_{{ table.name | upper }}_ACTION_{{ action.name | upper }},

{% endfor %}
} sai_{{ table.name }}_action_t;

{% endif %}
{% endfor %}
{% for table in sai_api.tables %}
{% if table.is_object == 'false' %}
/**
 * @brief Entry for {{ table.name }}
 */
typedef struct _sai_{{ table.name }}_t
{
    /**
     * @brief Switch ID
     *
     * @objects SAI_OBJECT_TYPE_SWITCH
     */
    sai_object_id_t switch_id;

{% for key in table['keys'] %}
    /**
     * @brief {{ key.match_type | capitalize | replace('Lpm', 'LPM') }} matched key {{ key.name }}
{% if key.type == 'sai_object_id_t' %}
     *
     * @objects SAI_OBJECT_TYPE_{{ key.object_name | upper }}
{% endif %}
     */
    {{ key.type }} {{ key.name | lower }};

{% if key.match_type == 'ternary' %}
    /**
     * @brief Ternary key {{ key.name }} mask
     */
    {{ key.type }} {{ key.name | lower }}_mask;

{% endif %}
{% endfor %}
{% if table['keys'] | selectattr('match_type', 'ne', 'exact') | list | length > 0 %}
{% if table['keys'] | selectattr('match_type', 'eq', 'lpm') | list | length == 0 %}
    /**
     * @brief Rule priority in table
     */
    sai_uint32_t priority;

{% endif %}
{% endif %}
} sai_{{ table.name }}_t;

{% endif %}
/**
 * @brief Attribute ID for {{ sai_api.app_name }}_{{ table.name }}
 */
typedef enum _sai_{{ table.name }}_attr_t
{
    /**
     * @brief Start of attributes
     */
    SAI_{{ table.name | upper }}_ATTR_START,

{% set ns = namespace(firstattr=false) %}
{% if table.actions | length > 1 or table.is_object == 'false' %}
    /**
     * @brief Action
     *
     * @type sai_{{ table.name }}_action_t
     * @flags CREATE_AND_SET
     * @default SAI_{{ table.name | upper }}_ACTION_{{ table.actions[0].name | upper }}
     */
    SAI_{{ table.name | upper }}_ATTR_ACTION = SAI_{{ table.name | upper }}_ATTR_START,

{% set ns.firstattr = true %}
{% endif %}
{% if table.is_object == 'true' %}
{% if table['keys'] | length > 1 %}
{% for key in table['keys'] %}
{% if key.isattribute != 'false' %}
    /**
     * @brief {{ key.match_type | capitalize | replace('Lpm', 'LPM') }} matched key {{ key.name }}
     *
     * @type {{ key.type }}
     * @flags MANDATORY_ON_CREATE | CREATE_ONLY
{% if key.type == 'sai_uint16_t' %}
     * @isvlan false
{% endif %}
{% if key.type == 'sai_object_id_t' %}
     * @objects SAI_OBJECT_TYPE_{{ key.name | replace('_id', '') | upper }}
{% endif %}
{% if key.isresourcetype == 'true' %}
     * @isresourcetype true
{% endif %}
     */
{% if not ns.firstattr %}
    SAI_{{ table.name | upper }}_ATTR_{{ key.name | upper }} = SAI_{{ table.name | upper }}_ATTR_START,
{% set ns.firstattr = true %}
{% else %}
    SAI_{{ table.name | upper }}_ATTR_{{ key.name | upper }},
{% endif %}

{% if key.match_type == 'ternary' %}
    /**
     * @brief Ternary matched mask {{ key.name }}
     *
     * @type {{ key.type }}
     * @flags MANDATORY_ON_CREATE | CREATE_ONLY
     */
    SAI_{{ table.name | upper }}_ATTR_{{ key.name | upper }}_MASK,

{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
{% for sai_attr in table.sai_attributes %}
{% if sai_attr.skipattr == 'true' %}
{% else %}
    /**
     * @brief Action {% for action in sai_attr.param_actions %}{{ action }}{{ ", " if not loop.last else "" }}{% endfor %} parameter {{ sai_attr.name | upper }}
     *
     * @type {{ sai_attr.type }}
{% if sai_attr.isreadonly == 'true' %}
     * @flags READ_ONLY
{% else if sai_attr.is_create_only == 'true' %}
     * @flags CREATE_ONLY
{% else %}
     * @flags CREATE_AND_SET
{% endif %}
{% if sai_attr.type == 'sai_uint16_t' %}
     * @isvlan false
{% endif %}
{% if sai_attr.type == 'sai_object_id_t' %}
     * @objects SAI_OBJECT_TYPE_{{ sai_attr.object_name | upper }}
     * @allownull true
{% endif %}
{% if sai_attr.isreadonly != 'true' %}
     * @default {{ sai_attr.default }}
{% endif %}
{% if table.actions | length > 1 %}
{% if sai_attr.param_actions | length > 0 %}
     * @validonly {% for action in sai_attr.param_actions %}SAI_{{ table.name | upper }}_ATTR_ACTION == SAI_{{ table.name | upper }}_ACTION_{{ action | upper }}{{ " or " if not loop.last else "" }}{% endfor %}

{% endif %}
{% endif %}
{% if sai_attr.validonly != None %}
     * @validonly {{ sai_attr.validonly }}
{% endif %}
{% if sai_attr.isresourcetype == 'true' %}
     * @isresourcetype true
{% endif %}
     */
{% if not ns.firstattr %}
    SAI_{{ table.name | upper }}_ATTR_{{ sai_attr.name | upper }} = SAI_{{ table.name | upper }}_ATTR_START,
{% set ns.firstattr = true %}
{% else %}
    SAI_{{ table.name | upper }}_ATTR_{{ sai_attr.name | upper }},
{% endif %}

{% endif %}
{% endfor %}
{% if table.with_counters == 'true' %}
    /**
     * @brief Attach a counter
     *
     * When it is empty, then packet hits won't be counted
     *
     * @type sai_object_id_t
     * @flags CREATE_AND_SET
     * @objects SAI_OBJECT_TYPE_COUNTER
     * @allownull true
     * @default SAI_NULL_OBJECT_ID
     */
{% if not ns.firstattr %}
    SAI_{{ table.name | upper }}_ATTR_COUNTER_ID = SAI_{{ table.name | upper }}_ATTR_START,
{% set ns.firstattr = true %}
{% else %}
    SAI_{{ table.name | upper }}_ATTR_COUNTER_ID,
{% endif %}

{% endif %}
{% if table.is_object == 'true' %}
{% if table['keys'] | selectattr('match_type', 'ne', 'exact') | list | length > 0 %}
{% if table['keys'] | selectattr('match_type', 'eq', 'lpm') | list | length == 0 %}
    /**
     * @brief Rule priority in table
     *
     * @type sai_uint32_t
     * @flags MANDATORY_ON_CREATE | CREATE_ONLY
     */
    SAI_{{ table.name | upper }}_ATTR_PRIORITY,

{% endif %}
{% endif %}
{% endif %}
{% if table.ipaddr_family_attr == 'true' %}
    /**
     * @brief IP address family for resource accounting
     *
     * @type sai_ip_addr_family_t
     * @flags READ_ONLY
     * @isresourcetype true
     */
    SAI_{{ table.name | upper }}_ATTR_IP_ADDR_FAMILY,

{% endif %}
    /**
     * @brief End of attributes
     */
    SAI_{{ table.name | upper }}_ATTR_END,

    /** Custom range base value */
    SAI_{{ table.name | upper }}_ATTR_CUSTOM_RANGE_START = 0x10000000,

    /** End of custom range base */
    SAI_{{ table.name | upper }}_ATTR_CUSTOM_RANGE_END,

} sai_{{ table.name }}_attr_t;

{% include 'templates/headers/sai_stats_enum.j2' %}
{% endfor %}
{% for table in sai_api.tables %}
/**
 * @brief Create {{ sai_api.app_name }}_{{ table.name }}
 *
{% if table.is_object == 'true' %}
 * @param[out] {{ table.name }}_id Entry id
 * @param[in] switch_id Switch id
{% else %}
 * @param[in] {{ table.name }} Entry
{% endif %}
 * @param[in] attr_count Number of attributes
 * @param[in] attr_list Array of attributes
 *
 * @return #SAI_STATUS_SUCCESS on success Failure status code on error
 */
typedef sai_status_t (*sai_create_{{ table.name }}_fn)(
{% if table.is_object == 'true' %}
        _Out_ sai_object_id_t *{{ table.name }}_id,
        _In_ sai_object_id_t switch_id,
{% else %}
        _In_ const sai_{{ table.name }}_t *{{ table.name }},
{% endif %}
        _In_ uint32_t attr_count,
        _In_ const sai_attribute_t *attr_list);

/**
 * @brief Remove {{ sai_api.app_name }}_{{ table.name }}
 *
{% if table.is_object == 'true' %}
 * @param[in] {{ table.name }}_id Entry id
{% else %}
 * @param[in] {{ table.name }} Entry
{% endif %}
 *
 * @return #SAI_STATUS_SUCCESS on success Failure status code on error
 */
typedef sai_status_t (*sai_remove_{{ table.name }}_fn)(
{% if table.is_object == 'true' %}
        _In_ sai_object_id_t {{ table.name }}_id);
{% else %}
        _In_ const sai_{{ table.name }}_t *{{ table.name }});
{% endif %}

/**
 * @brief Set attribute for {{ sai_api.app_name }}_{{ table.name }}
 *
{% if table.is_object == 'true' %}
 * @param[in] {{ table.name }}_id Entry id
{% else %}
 * @param[in] {{ table.name }} Entry
{% endif %}
 * @param[in] attr Attribute
 *
 * @return #SAI_STATUS_SUCCESS on success Failure status code on error
 */
typedef sai_status_t (*sai_set_{{ table.name }}_attribute_fn)(
{% if table.is_object == 'true' %}
        _In_ sai_object_id_t {{ table.name }}_id,
{% else %}
        _In_ const sai_{{ table.name }}_t *{{ table.name }},
{% endif %}
        _In_ const sai_attribute_t *attr);

/**
 * @brief Get attribute for {{ sai_api.app_name }}_{{ table.name }}
 *
{% if table.is_object == 'true' %}
 * @param[in] {{ table.name }}_id Entry id
{% else %}
 * @param[in] {{ table.name }} Entry
{% endif %}
 * @param[in] attr_count Number of attributes
 * @param[inout] attr_list Array of attributes
 *
 * @return #SAI_STATUS_SUCCESS on success Failure status code on error
 */
typedef sai_status_t (*sai_get_{{ table.name }}_attribute_fn)(
{% if table.is_object == 'true' %}
        _In_ sai_object_id_t {{ table.name }}_id,
{% else %}
        _In_ const sai_{{ table.name }}_t *{{ table.name }},
{% endif %}
        _In_ uint32_t attr_count,
        _Inout_ sai_attribute_t *attr_list);

{% include 'templates/headers/sai_stats_api.j2' %}
{% if table.is_object == 'false' %}
/**
 * @brief Bulk create {{ sai_api.app_name }}_{{ table.name }}
 *
 * @param[in] object_count Number of objects to create
 * @param[in] {{ table.name }} List of object to create
 * @param[in] attr_count List of attr_count. Caller passes the number
 *    of attribute for each object to create.
 * @param[in] attr_list List of attributes for every object.
 * @param[in] mode Bulk operation error handling mode.
 * @param[out] object_statuses List of status for every object. Caller needs to
 * allocate the buffer
 *
 * @return #SAI_STATUS_SUCCESS on success when all objects are created or
 * #SAI_STATUS_FAILURE when any of the objects fails to create. When there is
 * failure, Caller is expected to go through the list of returned statuses to
 * find out which fails and which succeeds.
 */
typedef sai_status_t (*sai_bulk_create_{{ table.name }}_fn)(
        _In_ uint32_t object_count,
        _In_ const sai_{{ table.name }}_t *{{ table.name }},
        _In_ const uint32_t *attr_count,
        _In_ const sai_attribute_t **attr_list,
        _In_ sai_bulk_op_error_mode_t mode,
        _Out_ sai_status_t *object_statuses);

/**
 * @brief Bulk remove {{ sai_api.app_name }}_{{ table.name }}
 *
 * @param[in] object_count Number of objects to remove
 * @param[in] {{ table.name }} List of objects to remove
 * @param[in] mode Bulk operation error handling mode.
 * @param[out] object_statuses List of status for every object. Caller needs to
 * allocate the buffer
 *
 * @return #SAI_STATUS_SUCCESS on success when all objects are removed or
 * #SAI_STATUS_FAILURE when any of the objects fails to remove. When there is
 * failure, Caller is expected to go through the list of returned statuses to
 * find out which fails and which succeeds.
 */
typedef sai_status_t (*sai_bulk_remove_{{ table.name }}_fn)(
        _In_ uint32_t object_count,
        _In_ const sai_{{ table.name }}_t *{{ table.name }},
        _In_ sai_bulk_op_error_mode_t mode,
        _Out_ sai_status_t *object_statuses);

{% endif %}
{% endfor %}
typedef struct _sai_{{ sai_api.app_name }}_api_t
{
{% set table_name_max = sai_api.tables|map(attribute="name")|map("length") | max %}
{% for table in sai_api.tables %}
{% set space_offset = table_name_max - table.name | length %}
    sai_create_{{ table.name }}_fn           {{ " " * space_offset }}create_{{ table.name }};
    sai_remove_{{ table.name }}_fn           {{ " " * space_offset }}remove_{{ table.name }};
    sai_set_{{ table.name }}_attribute_fn    {{ " " * space_offset }}set_{{ table.name }}_attribute;
    sai_get_{{ table.name }}_attribute_fn    {{ " " * space_offset }}get_{{ table.name }}_attribute;
{% include 'templates/headers/sai_stats_api_list.j2' %}
{% if table.is_object == 'true' %}
    sai_bulk_object_create_fn{{ " " * table_name_max }}create_{{ table.name }}s;
    sai_bulk_object_remove_fn{{ " " * table_name_max }}remove_{{ table.name }}s;
{% else %}
    sai_bulk_create_{{ table.name }}_fn      {{ " " * space_offset }}create_{{ table.name | replace("entry", "entries") }};
    sai_bulk_remove_{{ table.name }}_fn      {{ " " * space_offset }}remove_{{ table.name | replace("entry", "entries") }};
{% endif %}

{% endfor %}
} sai_{{ sai_api.app_name }}_api_t;

/**
 * @}
 */
#endif /** __SAIEXPERIMENTAL{{ sai_api.app_name | replace('_', '') | upper}}_H_ */

